using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using Barrage.Global;
using SlimDX;

namespace Barrage.GUI.Elements
{
    /// <summary>
    /// A button list is a list of GUIButtonListElement instances that are rendered inside a box on screen
    /// </summary>
    public class GUIButtonList : GUIElement
    {
        const string XML_TITLE_ATTRIBUTE = "title";
        const string XML_WIDTH_ATTRIBUTE = "width";
        const string XML_HEIGHT_ATTRIBUTE = "height";
        const string XML_LISTOPTION_ELEMENT = "ListOption";
        const string XML_LISTSLIDER_ELEMENT = "ListSlider";
        const string XML_LISTSELECTOR_ELEMENT = "ListSelect";
        const string XML_LISTCHECKBOX_ELEMENT = "ListCheckbox";
        const string XML_LISTCOLORPICKER_ELEMENT = "ListColorPicker";
        const string XML_LISTINPUT_ELEMENT = "ListInput";
        const string XML_LISTNUMBERSELECTOR_ELEMENT = "ListNumberSelect";
        
        private Vector2 size;
        /// <summary>
        /// Returns button list dimensions
        /// </summary>
        public Vector2 Size { get { return new Vector2(size.X,size.Y+OptionsHeight); } }

        string title;
        /// <summary>
        /// Gets / Sets list title
        /// </summary>
        public virtual string Title { get { return title; } set { title = value; } }

        /// <summary>
        /// Default size of the button list. Can be overrided
        /// </summary>
        protected virtual Vector2 DefaultSize { get { return new Vector2(100,100); } }

        List<GUIButtonListElement> options=new List<GUIButtonListElement>();
        /// <summary>
        /// List of button list's elements
        /// </summary>
        public List<GUIButtonListElement> Options { get { return options; } }

        /// <summary>
        /// Constructor. Loads other elements of the button list
        /// </summary>
        /// <param name="layout">Layout that will hold this item</param>
        /// <param name="template">Template that will be used to render this item</param>
        /// <param name="xn">Xml Node that holds attribute values of this item</param>
        public GUIButtonList(GUILayout layout, string template, XmlNode xn)
            : base(layout, template,xn)
        {
            size = XmlHelper.ParseXMLVector2Attribute(xn, XML_WIDTH_ATTRIBUTE, XML_HEIGHT_ATTRIBUTE, DefaultSize);

            title = Language.LanguageManager.Texts[XmlHelper.GetXMLAttribute(xn,XML_TITLE_ATTRIBUTE)];

            foreach (XmlNode xnc in xn.ChildNodes)
            {
                long initTime = Timer.DefaultTimer.CurrentTotalTime; 
                if (xnc.NodeType != XmlNodeType.Element) continue;
                
                switch (xnc.Name)
                {
                    case XML_LISTOPTION_ELEMENT:
                        AddElement(GUITemplateManager.CreateButtonListOption(layout, template, xnc));
                        break;
                    case XML_LISTSLIDER_ELEMENT:
                        AddElement(GUITemplateManager.CreateButtonListSlider(layout, template, xnc));
                        break;
                    case XML_LISTSELECTOR_ELEMENT:
                        AddElement(GUITemplateManager.CreateButtonListSelector(layout, template, xnc));
                        break;
                    case XML_LISTCHECKBOX_ELEMENT:
                        AddElement(GUITemplateManager.CreateButtonListCheckbox(layout, template, xnc));
                        break;
                    case XML_LISTCOLORPICKER_ELEMENT:
                        AddElement(GUITemplateManager.CreateButtonListColorPicker(layout, template, xnc));
                        break;
                    case XML_LISTINPUT_ELEMENT:
                        AddElement(GUITemplateManager.CreateButtonListTextInput(layout, template, xnc));
                        break;
                    case  XML_LISTNUMBERSELECTOR_ELEMENT:
                        AddElement(GUITemplateManager.CreateButtonListNumberSelector(layout, template, xnc));
                        break;
                }
                NLog.LogManager.GetLogger(ToString()).Debug("Element " + xnc.Name + " created in " + (Timer.DefaultTimer.CurrentTotalTime - initTime) + " ms");
            
            }
        }

        /// <summary>
        /// \internal Updates matrices and button list's subelements
        /// </summary>
        protected override void DoUpdate()
        {
            base.DoUpdate(); 
            foreach (GUIButtonListElement option in options)
            {
                option.Motion.Parent = Motion;
                option.Update();
            }
            
        }

        /// <summary>
        /// Adds a GUIButtonListElement instance to the options list
        /// </summary>
        /// <param name="option">Element to be added</param>
        protected void AddElement(GUIButtonListElement option)
        {
            options.Add(option);
            RepositionOptions();
            if (option.IsSelectable)
                Layout.Add(option.SelectableElement, false);
            else
                Layout.Add(option.Element, false);
        }


        float OptionsHeight
        {
            get
            {
                float height = 0;
                foreach (GUIButtonListElement option in options)
                {
                    height += option.Size.Y;
                }
                return height;
            }
        }

        /// <summary>
        /// \internal Renders the box and each item inside it
        /// </summary>
        protected override void DoRender()
        {
            base.DoRender();
            foreach (GUIButtonListElement option in options)
                option.Render();
        }

        void RepositionOptions()
        {
            float totalHeight = OptionsHeight;
            float partialHeight = 0;
            for (int i = 0; i < options.Count; i++)
            {
                options[i].Motion.Translation = new Vector3(0,  totalHeight / 2f - partialHeight - options[i].Size.Y / 2f, 0);
                partialHeight += options[i].Size.Y;
            }


        }

        /// <summary>
        /// \internal Clear resources
        /// </summary>
        public override void Dispose()
        {
            options.Clear();
            options = null;
            base.Dispose();
        }
    }
}
